import os
import random
import smtplib
import string
import time
from datetime import datetime, timedelta
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header
from email import utils
from email.mime.application import MIMEApplication
from pathlib import Path

from fastapi import HTTPException
from core.config import settings
from models import ZhanEmailCode, ZhanUser


class Email(object):
    body = '''您的验证码为: {code}'''
    to_pf = None

    def __init__(self):
        self.message = None
        self.from_addr = settings.EMAIL_ADDRESS
        self.password = settings.EMAIL_PASSWORD
        # self.to_addr = to_addr
        self.smtp_server = settings.EMAIL_SERVICE
        self.smtp_port = settings.EMAIL_PORT

    def add_body(self, params: dict, to_pf, template_id: str = 'register'):
        self.to_pf = to_pf
        self.message = MIMEMultipart()  # 创建邮件
        self.message['From'] = Header(self.from_addr)
        self.message['To'] = Header(self.to_pf)
        self.message['Message-ID'] = utils.make_msgid()
        # self.message['Date'] = Header(datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S'))
        subject = 'Welcome to OPEN APP'
        self.message['Subject'] = Header(subject, 'utf-8')
        seed_time = time.strftime('%Y{y}%m{m}%d{d}').format(y='年', m='月', d='日')
        self.body = Email.read_email_template(template_id, params)
        self.message.attach(MIMEText(self.body, 'html', 'utf-8'))

    @staticmethod
    def read_email_template(template_id, params):
        root_path = Path(__file__).resolve(strict=True).parent.parent.parent
        path_file = os.path.join(root_path, f'static/{template_id}.html')
        with open(path_file, mode='r', encoding='utf-8') as f:
            html_content = f.read()
        template = string.Template(html_content)
        result = template.substitute(code=params['code'])
        return result

    def send_letter(self):
        server = smtplib.SMTP_SSL(self.smtp_server, self.smtp_port)
        server.ehlo()
        server.login(self.from_addr, self.password)
        server.sendmail(self.from_addr, self.to_pf, self.message.as_string())
        server.quit()


class EmailService(object):

    @staticmethod
    async def verify_email(email):
        now_date = datetime.utcnow() - timedelta(minutes=5)
        email_code_items = await ZhanEmailCode.filter(email=email, created_at__gt=now_date).count()
        count = email_code_items
        await EmailService.use_code(email)
        if count >= 5:
            raise HTTPException(status_code=400, detail="Requests are too frequent, please try again later")

    @staticmethod
    async def verify_code(email, code):
        now_date = datetime.utcnow() - timedelta(minutes=5)
        email_code_items = await ZhanEmailCode.filter(
            email=email,
            code=code,
            created_at__gt=now_date,
            status=ZhanEmailCode.STATUS_NOT_VERIFY).first()
        if not email_code_items:
            raise HTTPException(status_code=400, detail="The verification code has expired")

    @staticmethod
    async def verify_email_user(email):
        user_item = await ZhanUser.filter(username=email).first()
        if user_item:
            raise HTTPException(status_code=400, detail="The current mailbox has already been registered")

    @staticmethod
    async def verify_email_user_forgot(email):
        user_item = await ZhanUser.filter(username=email).first()
        if not user_item:
            raise HTTPException(status_code=400, detail="The user was not found")

    @staticmethod
    async def use_code(email, code=None):
        now_date = datetime.utcnow() - timedelta(minutes=5)
        email_code_items = ZhanEmailCode.filter(
            email=email,
            created_at__gt=now_date,
            status=ZhanEmailCode.STATUS_NOT_VERIFY)
        if code:
            email_code_items = email_code_items.filter(code=code)
        await email_code_items.update(status=ZhanEmailCode.STATUS_VERIFY)

    @staticmethod
    async def send_email_code(email, email_type=ZhanEmailCode.EMAIL_TYPE_REGISTER):
        await EmailService.verify_email(email)
        code = ''.join(random.choices(string.digits, k=6))
        await ZhanEmailCode.create(code=code, email=email, email_type=email_type)
        email_object = Email()
        email_object.add_body(
            {"code": code}, email
        )
        email_object.send_letter()
